﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Collections;
using System.Collections.Specialized;

using ECCIT;

namespace ECCIT.Xml
{
    public class SchemaValidator
    {
        private static bool _bIsValid = false;
        private static Dictionary<ValidationEventArgs, string> _oSchemaValidationErrors = new Dictionary<ValidationEventArgs,string>();

        public static ResultInfo Validate (string sourceXmlDirectory, string schemaDirectory, StatusOutputHandler statusOutputHandler)
        {
            _oSchemaValidationErrors.Clear();   // clear the static dictionary

            ResultInfo result = ResultInfo.CreateInstance (false, "");
            statusOutputHandler("XML 文件校验开始...");

            // check arguments
            if (sourceXmlDirectory == null)
            {
                result.Message = "The Xml file directory is null.";
                return result;
            }

            if (schemaDirectory == null)
            {
                result.Message = "The Schema file directory is null.";
                return result;
            }

            if (!Directory.Exists (sourceXmlDirectory))
            {
                result.Message = string.Format("The source xml directory: {0} does not exist.", sourceXmlDirectory);
                return result;
            }

            if (!Directory.Exists (schemaDirectory))
            {
                result.Message = string.Format("The schema directory: {0} does not exist.", schemaDirectory);
                return result;
            }

            try
            {
                //找出所有需要校验的xml文件
                string[] xmlFiles = Directory.GetFiles (sourceXmlDirectory, "*.xml");
                statusOutputHandler("共搜索到需要进行校验的 XML 文件数：" + xmlFiles.Length);

                //循环所有的xml文件
                foreach (string xmlFile in xmlFiles)
                    ValidateXml(xmlFile, schemaDirectory, statusOutputHandler);     //进行验证并返回验证结果，错误会存在静态变量_oSchemaValidationErrors里

                result.Result = true;
                result.Message = "XML 文件校验结束！";
                result.ReturnObject = _oSchemaValidationErrors;
            }
            catch (Exception ex)
            {
                result.Message = "校验 XML 文件发生异常，异常信息：" + ex.Message;
            }

            statusOutputHandler(result.Message);
            return result;
        }

        //验证 XML 文件
        private static bool ValidateXml(string sXmlFileName, string schemaPath, StatusOutputHandler statusOutputHandler)
        {
            try
            {
                //relocate the parm check here to let the exception to be caught by this method's CATCH
                if (sXmlFileName == null || sXmlFileName.Length == 0)
                    throw new ArgumentNullException ("sXmlFileName");

                if (!File.Exists (sXmlFileName))
                    throw new FileNotFoundException ("Xml file not found", sXmlFileName);

                statusOutputHandler(string.Format("文件：{0} 校验开始...", sXmlFileName));

                XmlSchemaCollection oSchemas = GetSchemaCollection (sXmlFileName, schemaPath);

                XmlTextReader textReader = new XmlTextReader (sXmlFileName);
                textReader.WhitespaceHandling = WhitespaceHandling.None;
                XmlValidatingReader oValidReader = new XmlValidatingReader (textReader);
                try
                {
                    oValidReader.Schemas.Add (oSchemas);
                    oValidReader.ValidationType = ValidationType.Schema;

                    // Set the validation event handler
                    oValidReader.ValidationEventHandler +=
                        new ValidationEventHandler (oValidReader_ValidationEventHandler);

                    while (oValidReader.Read ()) { }
                }
                finally
                {
                    oValidReader.Close ();
                    textReader.Close ();

                    statusOutputHandler(string.Format("文件：{0} 校验结束！", sXmlFileName));
                }
            }
            catch (Exception e)
            {
                _bIsValid = false;
                statusOutputHandler(string.Format("文件：{0} 校验时发生异常。异常信息：{1}", sXmlFileName, e.Message));
            }

            return _bIsValid;
        }

        //获取XML文件使用的XSD文件
        private static XmlSchemaCollection GetSchemaCollection (string sInputXmlFile, string sSchemaPath)
        {
            //check parms
            if (sInputXmlFile == null || sInputXmlFile.Length == 0)
                throw new ArgumentNullException ("sInputXmlFile");

            XmlSchemaCollection oReturnCol = new XmlSchemaCollection ();
            string schemaPath = Path.Combine (sSchemaPath, sInputXmlFile.Substring (sInputXmlFile.LastIndexOf ("\\") + 1).Replace (".xml", ".xsd"));
            oReturnCol.Add (null, schemaPath);
            return oReturnCol;
        }

        //Schema校验发生错误时触发的函数
        private static void oValidReader_ValidationEventHandler (object sender, ValidationEventArgs e)
        {
            try
            {
                _oSchemaValidationErrors.Add (e, "File: " + Path.GetFileName (e.Exception.SourceUri) + ", Line: " + e.Exception.LineNumber + ", Details: " + e.Exception.Message);
            }
            catch (Exception exc)
            {
                NameValueCollection nvcInfo = new NameValueCollection ();
                nvcInfo.Add ("e.Message", e.Message); //only show first 200 chars of mesg in case it can be huge.
            }
            finally
            {
                _bIsValid = false;
            }
        }
    }
}
